package com.me.seckill.config;

import com.crossoverjie.distributed.intercept.SpringMVCIntercept;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.module.paramnames.ParameterNamesModule;
import com.me.seckill.filter.MyFilter;
import com.me.seckill.interceptor.TokenInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.util.List;
import java.util.Objects;

/**
 * WebMvcConfigurerAdapter 以废弃，推荐实现 WebMvcConfigurer 接口
 *
 * @author ME
 */
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {

	@Autowired(required = false)
	private TokenInterceptor tokenInterceptor;

	@Value("${xssFilter.excludedUrl:''}")
	private String excludedUrl;

	@Value("${xssFilter.excludeParameter:\"\"}")
	private String excludeParameter;

	/**
	 * 当配置 `com.me.token.enable = true` 时，声明的 @Bean 生效。
	 * 默认情况下，未配置 `com.me.token.enable` 识别为 不匹配，可通过修改 `matchIfMissing` 改变策略
	 */
	@Bean
	@ConditionalOnProperty(prefix = "com.me.token", name = "enable", havingValue = "true", matchIfMissing = true)
	public TokenInterceptor tokenInterceptor() {
		return new TokenInterceptor();
	}

	/**
	 * 当前 @Bean 与 yml配置 `spring.jackson.generator.WRITE_NUMBERS_AS_STRINGS=true` 保留一个即可，<p>
	 * 	但是不推荐配置 `WRITE_NUMBERS_AS_STRINGS`，所有 number类型 都转成 String，颗粒度太大
	 * @return
	 */
	@Bean
	public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer() {
		Jackson2ObjectMapperBuilderCustomizer cunstomizer = new Jackson2ObjectMapperBuilderCustomizer() {
			@Override
			public void customize(Jackson2ObjectMapperBuilder jacksonObjectMapperBuilder) {
				jacksonObjectMapperBuilder.serializerByType(Long.TYPE, ToStringSerializer.instance)
						.serializerByType(Long.class, ToStringSerializer.instance);
				// 引入 JavaTimeModule等依赖后，会自动注册进来，无需手动注册
				// jacksonObjectMapperBuilder.modulesToInstall(new JavaTimeModule(), new Jdk8Module(), new ParameterNamesModule());
			}
		};

		return cunstomizer;
	}

	/**
	 * 自定义 Filter 只需要增加 `@Component` 注解，可指定 order，但是不能指定 url规则
	 */
	@Bean
	public FilterRegistrationBean<MyFilter> myFilterRegistration() {
		FilterRegistrationBean<MyFilter> registration = new FilterRegistrationBean<>();
		registration.setFilter(new MyFilter());
		registration.addUrlPatterns("/*");
		registration.addInitParameter("excludedUrl", excludedUrl);
		registration.addInitParameter("excludeParameter", excludeParameter);
		registration.setName("myFilter");
		registration.setOrder(Integer.MAX_VALUE);
		return registration;
	}

	@Bean
	public SpringMVCIntercept redisLimit() {
		return new SpringMVCIntercept();
	}

	@Override
	public void addInterceptors(InterceptorRegistry registry) {
		registry.addInterceptor(redisLimit()).addPathPatterns("/**");

		if (Objects.nonNull(tokenInterceptor)) {
			registry.addInterceptor(tokenInterceptor)
					.addPathPatterns("/**")
					.excludePathPatterns("/error", "/auth/**", "/swagger-resources/**", "*.js", "/**/*.js", "*.css", "/**/*.css", "*.html", "/**/*.html", "/ecloud-job-admin/toLogin");
		}
	}

}
